#include <am.h>
#include <riscv32.h>


static _Context* (*user_handler)(_Event, _Context*) = NULL;
void __am_get_cur_as(_Context *c);
void __am_switch(_Context *c);

_Context* __am_irq_handle(_Context *c) {
  __am_get_cur_as(c);
  _Context *next = c;
  uint32_t* ret_targ = &(c->epc);

  // printf("scause = %x sstatus=%x sepc=%x\n",c->cause,c->status,c->epc);

  if (user_handler) {
    _Event ev = {0};
    switch (c->cause) {
      case EVENT_ECALL: 
        ev.event = ((uint32_t)c->GPR1 == -1 ? _EVENT_YIELD : _EVENT_SYSCALL);//_EVENT_SYSCALL; 
        *ret_targ = c->epc + 4;
        asm volatile("csrw sepc, %0" : : "r"(ret_targ));
        break;
      default: ev.event = _EVENT_ERROR; break;
    }

    next = user_handler(ev, c);
    if (next == NULL) {
      next = c;
    }
  }
  __am_switch(c);
  return next;
}

extern void __am_asm_trap(void);

int _cte_init(_Context*(*handler)(_Event, _Context*)) {
  // initialize exception entry
  asm volatile("csrw stvec, %0" : : "r"(__am_asm_trap));

  // register event handler
  user_handler = handler;

  return 0;
}

_Context *_kcontext(_Area stack, void (*entry)(void *), void *arg) {
  _Context* ctx = stack.end - sizeof(_Context);
  uint32_t* cp = stack.start;
  ctx->epc = (uintptr_t)entry;
  ctx->status = (uintptr_t)0x0;
  *cp = (uint32_t)ctx;
  return ctx;
}

void _yield() {
  asm volatile("li a7, -1; ecall");
}

int _intr_read() {
  return 0;
}

void _intr_write(int enable) {
}
